package org.multimedia.jolitorask.extension.calendar.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Random;

import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.filter.Filter;
import net.fortuna.ical4j.filter.PeriodRule;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Dur;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.component.VAlarm;
import net.fortuna.ical4j.model.component.VEvent;

public class AlarmParser{
	
	private Calendar calendar;
	private Date startDate;
	
	private Connection c;
	private Statement s;
	
	private int id_calendar;

	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	private SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMddHHmm.ss");
	
	private static final String reqChannel = "SELECT CONCAT(\'SIP/\', `sip_buddies`.`name`) AS sip "
		+ "FROM `sip_buddies`, `telephones` JOIN `telephone2sip` ON `telephones`.`id_telephone`=`telephone2sip`.`id_telephone`, "
		+ "`ical_calendars` JOIN `utilisateur2buddy` ON `ical_calendars`.`utilisateur` = `utilisateur2buddy`.`id_utilisateur` "
		+ "WHERE `sip_buddies`.`id`= `utilisateur2buddy`.`id_buddy` "
		+ "AND `sip_buddies`.`id` = `telephone2sip`.`id_buddy` "
		+ "AND `telephones`.`nom` = ? "
		+ "AND `ical_calendars`.`id_calendar` = ?";
	

	public AlarmParser(Connection connexion, int id, URL fichier) {
		
		InputStream fin;

		this.id_calendar = id;

		try {
			
			/* Construit le iCalendar */
			fin = fichier.openStream();
			CalendarBuilder builder = new CalendarBuilder();
			calendar = builder.build(fin);
			
			/* Recupere la date du premier jour de la semaine */
			startDate = getStartWeekDate();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserException e) {
			e.printStackTrace();
		}
		
		try {
			c = connexion;
			s = c.createStatement();
		} catch (SQLException e) {
			e.printStackTrace();
		}
			
	}
	
	/**
	 * Parse le iCalendar
	 */
	@SuppressWarnings("unchecked")
	public void parse(){
	
			Period period = new Period(new DateTime(startDate), new Dur(1));
			Filter filter = new Filter(new PeriodRule(period));
			long start;

			/* On prend les evenement de la semaine */
			Iterator<Component> eventsOfCurrentWeek = filter.filter(calendar.getComponents(Component.VEVENT)).iterator();
			
			/* Pour tout les evenement */
			while(eventsOfCurrentWeek.hasNext()){
				
				VEvent event = (VEvent)eventsOfCurrentWeek.next();
				
				if( event.getSummary() != null ){
					
					String summary = event.getSummary().getValue();
					String description = (event.getDescription()==null)?summary:event.getDescription().getValue();
				
					Iterator<Period> allPeriods = event.calculateRecurrenceSet(period).iterator();
					
					while(allPeriods.hasNext()){
						
						Period elem = allPeriods.next();
						start = elem.getStart().getTime();
						
						Iterator<VAlarm> alarms = event.getAlarms().iterator();
						while( alarms.hasNext() ){
							
							VAlarm alarm = alarms.next();
							addAlarm(alarm, start, summary, description);
						}
					}
				}
			}	
	}
	
	
	private void addAlarm(VAlarm alarm, long start, String summary, String description) {
		
		
		int repeat = 1;
		Date date = new Date(start);
		Dur duration = null;
		
		if( alarm.getTrigger() != null )
			if( alarm.getTrigger().getDuration() != null )
				date = alarm.getTrigger().getDuration().getTime(new Date(start));
		
		if( alarm.getRepeat() != null )
			repeat = alarm.getRepeat().getCount();
		
		if( alarm.getDuration() != null )
			duration = alarm.getDuration().getDuration();
		
		for(int i=0; i< repeat; i++){
			
			if(duration != null ){
				date = duration.getTime(date); 
			}

			insererAlarme( date, description, summary );
		}
		
	}

	/**
	 * Se place a la premiere seconde de la semaine (Lundi 00h00min00s00)
	 * @return la date du debut de la semaine
	 */
	private Date getStartWeekDate(){
		
		java.util.Calendar cal = java.util.Calendar.getInstance();
		cal.setTime(new Date());
		cal.set(java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.MONDAY);
		cal.set(java.util.Calendar.HOUR_OF_DAY, 0);
		cal.set(java.util.Calendar.MINUTE, 0);
		cal.set(java.util.Calendar.SECOND, 0);
		cal.set(java.util.Calendar.MILLISECOND, 0);
		
		return cal.getTime();
	}
	
	private void insererAlarme( Date date, String message, String telephone ){

		/* on recup l id du phone */
		try{
		

			ResultSet rs = s.executeQuery ( "SELECT max(priority)+1 AS ligne FROM `sip_extensions` WHERE `exten` = 999 AND `context` = 'alarms';" );

			if(rs.next()){

				int ligne = rs.getInt("ligne");
				
				if(ligne == 0 )
					ligne = 1;

				/* Dans ical_alarms */
				s.execute ( "INSERT INTO `ical_alarms` (`id_alarm`, `calendar`, `date`, `message`) VALUES (NULL, '"+id_calendar+"', '"+sdf.format(date)+"', '"+message+"');" );
				
				/* Dans extensions */
				s.execute ( "INSERT INTO `sip_extensions` (`id`, `context`, `exten`, `priority`, `app`, `appdata`) VALUES (NULL, 'alarms', '999', '"+ligne+"', 'Answer', '');" );
				s.execute ( "INSERT INTO `sip_extensions` (`id`, `context`, `exten`, `priority`, `app`, `appdata`) VALUES (NULL, 'alarms', '999', '"+(ligne+1)+"', 'Wait', '3');" );
				s.execute ( "INSERT INTO `sip_extensions` (`id`, `context`, `exten`, `priority`, `app`, `appdata`) VALUES (NULL, 'alarms', '999', '"+(ligne+2)+"', 'System', 'dire \""+message+"\"');" );
				s.execute ( "INSERT INTO `sip_extensions` (`id`, `context`, `exten`, `priority`, `app`, `appdata`) VALUES (NULL, 'alarms', '999', '"+(ligne+3)+"', 'Background', 'tts');" );
				s.execute ( "INSERT INTO `sip_extensions` (`id`, `context`, `exten`, `priority`, `app`, `appdata`) VALUES (NULL, 'alarms', '999', '"+(ligne+4)+"', 'Hangup', '');" );
	
				creerFichier( ligne, date, telephone);

			}

		}catch( Exception e ) {

			e.printStackTrace();

		}

	}

	private void creerFichier( int ligne, Date date, String telephone ){

		try{
			/* chercher le telephone */
			PreparedStatement stmt = c.prepareStatement(reqChannel);
			stmt.setString(1, telephone);
			stmt.setInt(2, id_calendar);
			
			ResultSet rs = stmt.executeQuery();
			
			if(rs.next()){

				String channel = rs.getString("sip");
				String nom = "/tmp/alarm_"+System.currentTimeMillis()+"_"+new Random().nextInt(1000)+".call";
				
				File f = new File(nom);
				FileOutputStream out = new FileOutputStream(f);
				String channelS = "Channel: "+channel+"\n";
				String prioriteS = "Priority: "+ligne+"\n";    
				out.write(channelS.getBytes());

				out.write("CallerID: Jolitorask Reminder <999>\n".getBytes());
				out.write("MaxRetries: 5\n".getBytes());
				out.write("RetryTime: 300\n".getBytes());
				out.write("WaitTime: 45\n".getBytes());
				out.write("Context: alarms\n".getBytes());
				out.write("Extension: 999\n".getBytes());
				out.write(prioriteS.getBytes());

				/* changer la date */
				java.lang.Runtime.getRuntime().exec("touch -t "+sdf2.format(date)+" "+nom);

				/* deplacer */
				java.lang.Runtime.getRuntime().exec("mv "+nom+" /var/spool/asterisk/outgoing/");

			}
		}catch( Exception e ){

			e.printStackTrace();
		}


	}

}
